package common.project.epic.ui;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Timer;
import java.util.concurrent.Semaphore;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

import common.project.epic.core.IIOEpicService;
import common.project.epic.core.ILocationEpicService;
import common.project.epic.core.IOEpicService;
import common.project.epic.core.LocationEpicService;
import common.project.epic.db.CurrentUser;
import common.project.epic.db.EpicDBAdapter;
import common.project.epic.db.FileExtensionMap;
import common.project.epic.ui.EpicCreateMsg.LocServiceConnection;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TabActivity;  
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;  
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;  
import android.os.Environment;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TabHost;  
import android.widget.TextView;
import android.widget.Toast;
public class EpicNewMsg extends TabActivity implements OnClickListener, OnTabChangeListener{
    protected Resources res;
    
    private long msgDropTime;
    
    private String msgId;
    
    private long msgExpTime;
    private DatePicker msgExpTimeDP;
    private int expirationYear;
    private int expirationMonth;
    private int expirationDay;
    private static final long MAX_EXPIRATION_OFFSET_IN_SECONDS = 60*60*24*367; // 1 year in [s]
    
    private boolean deferredLocation = false;
    private double msgLat;
    private double msgLon;
    private double msgAlt;
    private Location currentLocation;
    private double currentLat;
	private double currentLon;
	private double currentAlt;
	private Location lastLocation;
	private double lastLat;
	private double lastLon;
	private double lastAlt;
	private Location defaultLocation;
	private double defaultLat;
	private double defaultLon;
	private double defaultAlt;
	private IconContextMenu iconContextMenu_location;
	private final int CONTEXT_MENU_LOCATION_ID = 7;
	protected final static int DEFERRED_LOCATION = 1;
	protected final static int WITHOUT_LOCATION = 2;
	protected final static int DEFAULT_LOCATION = 3;
	protected final static int LAST_LOCATION = 4;
    private int msgGeoSpan;
    private ImageButton setGeoButton;
	// geo span RadioButtons
	private RadioButton span1RB;
	private RadioButton span2RB;
	private RadioButton span3RB;
	private RadioButton span4RB;
    // geo span constants
    private static final int SPAN_100m = 10; // [tens of meters]
	private static final int SPAN_1km = 100; // [tens of meters]
	private static final int SPAN_10km = 1000; // [tens of meters]
	private static final int SPAN_650km = 65000; // [tens of meters]
	// map sub-activity id
	private static final int MAP_SUBACTIVITY = 11;
    
    private boolean[] msgCategories = new boolean[NUMBER_OF_CATEGORIES];
    // categories CheckBoxes
 	private CheckBox generalCB;
 	private CheckBox gamesCB;
 	private CheckBox advertisementsCB;
 	private CheckBox suggestionsCB;
 	private CheckBox eventsCB;
 	// categories IDs 
 	private static final int GENERAL_CATEGORY = 1;
 	private static final int GAMES_CATEGORY = 2;
 	private static final int ADVERTISEMENTS_CATEGORY = 3;
 	private static final int SUGGESTIONS_CATEGORY = 4;
 	private static final int EVENTS_CATEGORY = 5;
 	// categories constants
 	public static final int NUMBER_OF_CATEGORIES = 16;
 	private static final boolean[] DEFAULT_MSG_CATEGORIES = {true,false,false,false,
 															false,false,false,false,
 															false,false,false,false,
 															false,false,false,false};
    
    private String creatorUsername;
    private String creatorNickname;
    private String creatorId;
    private int hopCount;
    
    private double msgRate;
    
    private long crcCheck;
    
    private String msgTitle;
    private String msgContent;
    private EditText msgContentET;
    private EditText msgTitleET;
    
    public static final int ATTACH_IMAGE = 1;
    public static final int ATTACH_AUDIO = 2;
    public static final int ATTACH_VIDEO = 3;
    public static final int ATTACH_FILE = 4;
    private static int MAX_MSG_SIZE = 5000000; // [bytes] 
    private static int MAX_TITLE_LENGTH = 80; // [bytes]
    private static int MAX_CONTENT_LENGTH = 1600; // [bytes]
    private int spaceUsed;    
    private String attachmentsExtension;
    private String attachmentsPath;
    private ListView attachmentsList;
	private MyArrayAdapter adapter;
	private ArrayList<AttachmentElement> attachmentsArrayList = new ArrayList();
	private Button attachImageButton;
	private Button attachAudioButton;
	private Button attachVideoButton;
	private Button attachFileButton;
	private Button takePictureButton;
	private Button takeAudioButton;
	private class AttachmentElement implements Serializable {
		private static final long serialVersionUID = 1L;
		private void writeObject(java.io.ObjectOutputStream out) throws IOException {
		    out.writeUTF(attachmentExtension);
		    out.writeUTF(attachmentOriginalPath);
		    out.writeInt(attachmentOriginalSize);
		    out.writeUTF(attachmentPath);
		    out.writeInt(attachmentSize);
		}
		private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
			attachmentExtension = in.readUTF();
			attachmentOriginalPath = in.readUTF();
			attachmentOriginalSize = in.readInt();
			attachmentPath = in.readUTF();
			attachmentSize = in.readInt();
		}
		private String attachmentExtension;
    	private String attachmentOriginalPath;
    	private int attachmentOriginalSize;
    	private String attachmentPath;
    	private int attachmentSize;
    	public AttachmentElement(String ext, String oPath, int oSize, String path, int size) {
    		this.attachmentExtension = ext;
    		this.attachmentOriginalPath = oPath;
    		this.attachmentOriginalSize = oSize;
    		this.attachmentPath = path;
    		this.attachmentSize = size;
    	}
    	public String getAttachmentExtension() {return attachmentExtension;}
    	public String getAttachmentOriginalPath() {return attachmentOriginalPath;}
    	public int getAttachmentOriginalSize() {return attachmentOriginalSize;}
    	public String getAttachmentPath() {return attachmentPath;}
    	public int getAttachmentSize() {return attachmentSize;}
    	public void setAttachmentExtension(String ext) {this.attachmentExtension = ext;}
    	public void setAttachmentOriginalPath(String oPath) {this.attachmentOriginalPath = oPath;}
    	public void setAttachmentOriginalSize(int oSize) {this.attachmentOriginalSize = oSize;}
    	public void setAttachmentPath(String path) {this.attachmentPath = path;}
    	public void setAttachmentSize(int size) {this.attachmentSize = size;}
    }
	static class ViewHolder {
		protected TextView holdText;
		protected ImageView holdImage;
	}
	private class MyArrayAdapter extends ArrayAdapter<AttachmentElement> {
		private final Activity context;
		private final ArrayList<AttachmentElement> attachmentsArrayList;
		public MyArrayAdapter(Activity context, ArrayList<AttachmentElement> list) {
			super(context, R.layout.attachmentitem, list);
			this.context = context;
			this.attachmentsArrayList = list;
		}
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			final ViewHolder viewHolder;
			if(convertView==null) {
				LayoutInflater inflater = context.getLayoutInflater();
				convertView = inflater.inflate(R.layout.attachmentitem, null, true);
				viewHolder = new ViewHolder();
				viewHolder.holdText = (TextView) convertView.findViewById(R.id.attachmentNameTV);
				viewHolder.holdImage = (ImageView) convertView.findViewById(R.id.attachmentPreviewIV);
				convertView.setTag(viewHolder);
			}
			else {
	            viewHolder = (ViewHolder) convertView.getTag();
			}
			if (attachmentsArrayList.get(position).getAttachmentExtension().equals("jpeg")) {
				// set preview
				// viewHolder.holdImage.setImageResource();
			} 
			else {
				// set standard or mime preview
				// viewHolder.holdImage.setImageResource(R.drawable.icon);
			}
			viewHolder.holdText.setText((attachmentsArrayList.get(position).getAttachmentPath())
					.split("/")[((attachmentsArrayList.get(position).getAttachmentPath()).split("/")).length-1]);
			return convertView;
		}
	}
    
    private String carrierUserName;
    private long deliveryTime;
    private double deliveryLat;
    private double deliveryLon;
    private double deliveryAlt;
    
    private String loggedUserName;
    
    private boolean readFlag;
    private boolean deletedFlag;
    private boolean synchFlag;
    private boolean updatedFlag;
    private boolean deferredFlag;
    
    private long lastTxCopyTime;
    private int numberOfTxCopies;
    
    private EpicDBAdapter dbHelper;
    
//    IOEpicService mCommService;
//    LocationEpicService mLocationService;
    boolean mIOBound = false;
    boolean mLocBound = false;
	private ILocationEpicService mILocationEpicService = null;
	private IIOEpicService mIIOEpicService = null;
	private ServiceConnection mLocServiceConnection;    
    
	private boolean blowOnMic;
	private Button dropButton;
	private ImageView animation_IV;
	private MyAnimationDrawable animation;
	private Drawable frame;
	private boolean stopAnimation = false;
	private boolean isFirst = true;
	private boolean isLast = false;
	
	private String tmpDirString = "tmpDir";
	private boolean isSameActivity;
	private void deleteRecursive(File fileOrDirectory) {
	    if (fileOrDirectory.isDirectory()) {
	        for (File child : fileOrDirectory.listFiles()) {
	            deleteRecursive(child);
	        }
	    }
	    fileOrDirectory.delete();
	}
	
	@Override  
	public void onCreate(Bundle savedInstanceState) {  
		super.onCreate(savedInstanceState);  
		setContentView(R.layout.tabnewmsg);
		if(!isSameActivity) {
			String dirStr = getApplicationContext().getExternalCacheDir() + "/" + tmpDirString;
			File dirTmp = new File(dirStr);
			deleteRecursive(dirTmp);
		}
		isSameActivity = true;
		
		res = getResources();
		dbHelper = new EpicDBAdapter(this);

		CurrentUser.readCurrentUserSettings(getApplicationContext());
		
		Date dateNow = new Date();
		msgDropTime = (dateNow.getTime()/1000);
		
		// typical expiration time set in SETTINGS
		msgExpTime = msgDropTime + CurrentUser.getDefaultMsgTimeSpan();
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(msgExpTime*1000);
        expirationYear = calendar.get(Calendar.YEAR);
        expirationMonth = calendar.get(Calendar.MONTH);
        expirationDay = calendar.get(Calendar.DAY_OF_MONTH);        
        calendar.set(expirationYear, expirationMonth, expirationDay, 23, 59);
        
        // bind activity to location service 
        Intent intentloc = new Intent(this, LocationEpicService.class);
    	mLocServiceConnection = new LocServiceConnection();
        if(bindService(intentloc, mLocServiceConnection, Context.BIND_AUTO_CREATE)){}
        else{
        	Log.d("EPIC CREATE MSG", "NOT BINDED TO LOCATION SERVICE");
        	Toast.makeText(getApplicationContext(), "Location not available", Toast.LENGTH_LONG).show();
        };
        try {
			currentLocation = (Location) mILocationEpicService.refreshLocation();			
		} 
		catch (Exception e) {e.printStackTrace();}
		
		// message ID 
		String user_mac_string = BluetoothAdapter.getDefaultAdapter().getAddress();
		String[] user_mac_string_array = user_mac_string.split(":");
		msgId = "" + user_mac_string_array[4] + user_mac_string_array[5] + msgDropTime;
	    
		TabHost tabHost = getTabHost();  
		
		tabHost.setOnTabChangedListener(this);
		
		TabHost.TabSpec spec;  
		spec = tabHost.newTabSpec("edittext")
				.setIndicator("Edit Text",res.getDrawable(R.drawable.ic_tab1_newmsg))
				.setContent(R.id.layoutTab1);  
		tabHost.addTab(spec);  
		spec = tabHost.newTabSpec("setcategories")
				.setIndicator("Set Categories",res.getDrawable(R.drawable.ic_tab2_newmsg))
				.setContent(R.id.layoutTab2);
		tabHost.addTab(spec);  
		spec = tabHost.newTabSpec("setgeoproperties")
				.setIndicator("Set Geo Properties",res.getDrawable(R.drawable.ic_tab3_newmsg))
				.setContent(R.id.layoutTab3);
		tabHost.addTab(spec);  
		spec = tabHost.newTabSpec("settimeproperties")
				.setIndicator("Set Time Properties",res.getDrawable(R.drawable.ic_tab4_newmsg))
				.setContent(R.id.layoutTab4);
		tabHost.addTab(spec);  
		spec = tabHost.newTabSpec("addattachments")
				.setIndicator("Add Attachments",res.getDrawable(R.drawable.ic_tab5_newmsg))
				.setContent(R.id.layoutTab5);
		tabHost.addTab(spec);  
		tabHost.setCurrentTab(0);
		setTabColor(tabHost);
		msgTitleET = (EditText)findViewById(R.id.tabnewmsg_epicmsg_title_ET);
		msgContentET = (EditText)findViewById(R.id.tabnewmsg_epicmsg_note_ET);
		
//		msgCategories = DEFAULT_MSG_CATEGORIES;
		String msgCatStr = CurrentUser.getTypicalCategories();
		for(int i=0; i<NUMBER_OF_CATEGORIES; i++) {
			if(msgCatStr.charAt(i)=='1') {msgCategories[i] = true;}
			else {msgCategories[i] = false;}
		}
		generalCB = (CheckBox)findViewById(R.id.tabnewmsg_general_CB);
		gamesCB = (CheckBox)findViewById(R.id.tabnewmsg_games_CB);
		advertisementsCB = (CheckBox)findViewById(R.id.tabnewmsg_advertisements_CB);
		suggestionsCB = (CheckBox)findViewById(R.id.tabnewmsg_suggestions_CB);
	 	eventsCB = (CheckBox)findViewById(R.id.tabnewmsg_events_CB);
	 	generalCB.setOnClickListener(this);
	 	gamesCB.setOnClickListener(this);
	 	advertisementsCB.setOnClickListener(this);
	 	suggestionsCB.setOnClickListener(this);
	 	eventsCB.setOnClickListener(this);
	 	generalCB.setChecked(msgCategories[0]);
	 	gamesCB.setChecked(msgCategories[1]);
	 	advertisementsCB.setChecked(msgCategories[2]);
	 	suggestionsCB.setChecked(msgCategories[3]);
	 	eventsCB.setChecked(msgCategories[4]);
	 	
	 	// typical geographic span
	 	msgGeoSpan = CurrentUser.getDefaultMsgGeoSpan();
	 	setGeoButton = (ImageButton)findViewById(R.id.tabnewmsg_setGeoButton); 
        span1RB = (RadioButton)findViewById(R.id.tabnewmsg_span1_RB);
		span2RB = (RadioButton)findViewById(R.id.tabnewmsg_span2_RB);
		span3RB = (RadioButton)findViewById(R.id.tabnewmsg_span3_RB);
		span4RB = (RadioButton)findViewById(R.id.tabnewmsg_span4_RB);
		setGeoButton.setOnClickListener(this);
		span1RB.setOnClickListener(this);
		span2RB.setOnClickListener(this);
		span3RB.setOnClickListener(this);
		span4RB.setOnClickListener(this);
		if(msgGeoSpan==SPAN_100m) {
			span1RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_1km) {
			span2RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_10km) {
			span3RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_650km) {
			span4RB.setChecked(true);
		}
		
		
		msgExpTimeDP = (DatePicker)findViewById(R.id.tabnewmsg_datePicker);
		msgExpTimeDP.init(expirationYear, expirationMonth, expirationDay, onDateChangedListener);
		
		attachImageButton = (Button)findViewById(R.id.tabnewmsg_attachImage);
		attachAudioButton = (Button)findViewById(R.id.tabnewmsg_attachAudio);
		attachVideoButton = (Button)findViewById(R.id.tabnewmsg_attachVideo);
		attachFileButton = (Button)findViewById(R.id.tabnewmsg_attachFile);
		takePictureButton = (Button)findViewById(R.id.tabnewmsg_takePicture);
		takeAudioButton = (Button)findViewById(R.id.tabnewmsg_takeAudio);
		attachImageButton.setOnClickListener(this);
		attachAudioButton.setOnClickListener(this);
		attachVideoButton.setOnClickListener(this);
		attachFileButton.setOnClickListener(this);
		takePictureButton.setOnClickListener(this);
		takeAudioButton.setOnClickListener(this);
		attachmentsList = (ListView)findViewById(R.id.tabnewmsg_attachmentsLV);
		attachmentsList.setDividerHeight(2);
		adapter = new MyArrayAdapter(this, attachmentsArrayList);
		attachmentsList.setAdapter(adapter);
		attachmentsList.setEmptyView(findViewById(R.id.tabnewmsg_attachmentsEmptyTV));
		attachmentsList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
				AttachmentElement item = (AttachmentElement) adapterView.getItemAtPosition(position);
				Intent intent = new Intent();
				intent.setAction(android.content.Intent.ACTION_VIEW);
				File file = new File(item.getAttachmentPath());
				intent.setDataAndType(Uri.fromFile(file), "*/*");
				startActivity(intent); 
			}
		});
		attachmentsList.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
				AttachmentElement aeTmp = attachmentsArrayList.get(position);
				String filePath = aeTmp.attachmentPath;
				File file = new File(filePath);
				if(file.delete()) {
					Log.d("EpicNewMsg", "file deleted");
					spaceUsed = spaceUsed - aeTmp.getAttachmentSize(); 
					Log.d("EpicNewMsg", "spaceUsed="+spaceUsed);
					attachmentsArrayList.remove(position);
					adapter.notifyDataSetChanged();
					Log.d("EpicNewMsg", "Attachment deleted");
					if(attachmentsArrayList.isEmpty()) {
						File cachePath = getApplicationContext().getExternalCacheDir();
//						String dirPath = cachePath + "/" + msgId;
						String dirPath = cachePath + "/" + tmpDirString;
	               	    File dir = new File(dirPath);
	               	    if(dir.delete()) {
	               	    	Log.d("EpicNewMsg", "dir.delete() = directory deleted");
	               	    }
	               	    else {
	               	    	Log.d("EpicNewMsg", "dir.delete() = directory NOT deleted");
	               	    }
					}
				}
				else {
					Log.d("EpicNewMsg", "file NOT deleted");
				}
				return true;
			}
		});
		spaceUsed = MAX_TITLE_LENGTH + MAX_CONTENT_LENGTH;
		Log.d("EpicNewMsg", "spaceUsed="+spaceUsed);
		
		blowOnMic = CurrentUser.getBlowOnMic();
		dropButton = (Button)findViewById(R.id.tabnewmsg_epicmsg_viralButton);
		dropButton.setOnClickListener(this);
		animation_IV = (ImageView)findViewById(R.id.tabnewmsg_epicmsg_animation_IV);
    	
//    	animation_IV.setBackgroundResource(R.anim.animationslow);
//    	animation = (AnimationDrawable) animation_IV.getBackground();
    	
    	animation = new MyAnimationDrawable();
    	frame = res.getDrawable(R.drawable.dzero);
		animation.addFrame(frame, 400);
		frame = res.getDrawable(R.drawable.done);
		animation.addFrame(frame, 400);
		frame = res.getDrawable(R.drawable.dtwo); 
		animation.addFrame(frame, 400);
		frame = res.getDrawable(R.drawable.dthree); 
		animation.addFrame(frame, 400);
		frame = res.getDrawable(R.drawable.dfour); 
		animation.addFrame(frame, 400);
//		animation.setOneShot(false); 
		animation.setDuration(400); 
		animation_IV.setBackgroundDrawable(animation);
        
        //ACTION_SEND catching
        //check WHOIS calling intent
        //TODO check the reaction to intent calling and pass to initializeUI uri parameter, mime type parameter to fill each field
        //TODO add check for total file size: getFileSize method works only for MediaStore content provider files!
        Intent  callingIntent = getIntent();
        String action = callingIntent.getAction();
        Bundle extras = callingIntent.getExtras();
        if(action != null){
	        if(action.equals("SHARE_TO_EPIC")) {
		        if(extras.containsKey("content")) {
		        	final Uri selectedUri = (Uri) extras.getParcelable("content");
		        	int mime_type = extras.getInt("mime_type");
		        	if(mime_type!=ATTACH_IMAGE || mime_type!=ATTACH_AUDIO || mime_type!=ATTACH_VIDEO || mime_type!=ATTACH_FILE) {
		        		mime_type = ATTACH_FILE;
		        	}
		        	addAttachments(selectedUri, mime_type);
		        }
	        }
	        else if(action.equals("MULTIPLE_SHARE_TO_EPIC")) {
	        	if(extras.containsKey("content")) {
	        		ArrayList<Parcelable> selectedUri_list = extras.getParcelableArrayList("content");
		        	ArrayList<Integer> mime_type_list = extras.getIntegerArrayList("mime_type_list");
		        	int i=0;
		        	for(Integer item:mime_type_list) {
		        		Uri selectedUri = (Uri) selectedUri_list.get(i);
		        		int mime_type = (int) item;
			        	if(mime_type!=ATTACH_IMAGE || mime_type!=ATTACH_AUDIO || mime_type!=ATTACH_VIDEO || mime_type!=ATTACH_FILE) {
			        		mime_type = ATTACH_FILE;
			        	}
			        	addAttachments(selectedUri, mime_type);
		                i++;
		        	}
		        }
    		}
    	}
	}  	

	private DatePicker.OnDateChangedListener onDateChangedListener = new DatePicker.OnDateChangedListener() {
		@Override
		public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
			expirationYear = year;
            expirationMonth = monthOfYear;
            expirationDay = dayOfMonth;
            Calendar calendar = Calendar.getInstance();
            calendar.set(expirationYear, expirationMonth, expirationDay, 23, 59);
            Date date = new Date();
            long tNow = date.getTime()/1000;
            long tNowPlusOffset = tNow + MAX_EXPIRATION_OFFSET_IN_SECONDS;
            long msgExpTimeTmp = calendar.getTimeInMillis()/1000;
            if(msgExpTimeTmp<=tNow) {
            	// typical expiration time set in SETTINGS
        		msgExpTime = msgDropTime + CurrentUser.getDefaultMsgTimeSpan();
        		Calendar calendarTmp = Calendar.getInstance();
        		calendarTmp.setTimeInMillis(msgExpTime*1000);
                expirationYear = calendarTmp.get(Calendar.YEAR);
                expirationMonth = calendarTmp.get(Calendar.MONTH);
                expirationDay = calendarTmp.get(Calendar.DAY_OF_MONTH);        
                calendarTmp.set(expirationYear, expirationMonth, expirationDay, 23, 59);
                msgExpTimeDP.init(expirationYear, expirationMonth, expirationDay, onDateChangedListener);
            	Toast.makeText(getApplicationContext(), "Not allowed to set this withering period! \n" +
            			"Whitering: " + (CurrentUser.getDefaultMsgTimeSpan()/(60*60*24)) + " days from now", Toast.LENGTH_LONG).show();
            }
            else if(msgExpTimeTmp>=tNowPlusOffset) {
    			msgExpTime = tNowPlusOffset;
    			Calendar calendarTmp = Calendar.getInstance();
        		calendarTmp.setTimeInMillis(msgExpTime*1000);
                expirationYear = calendarTmp.get(Calendar.YEAR);
                expirationMonth = calendarTmp.get(Calendar.MONTH);
                expirationDay = calendarTmp.get(Calendar.DAY_OF_MONTH);        
                calendarTmp.set(expirationYear, expirationMonth, expirationDay, 23, 59);
                msgExpTimeDP.init(expirationYear, expirationMonth, expirationDay, onDateChangedListener);
            	Toast.makeText(getApplicationContext(), "Not allowed to set this withering period! \n" +
            			"Whitering: " + (MAX_EXPIRATION_OFFSET_IN_SECONDS/(60*60*24)) + " days from now", Toast.LENGTH_LONG).show();
            }
            else {
            	msgExpTime = msgExpTimeTmp;
            }
            Log.d("EpicNewMsg", "Expiration time set");
		}
	};
	
	@Override
	protected void onRestoreInstanceState(Bundle state) {
		super.onRestoreInstanceState(state);
		msgDropTime = state.getLong("msgDropTime");
		msgId = state.getString("msgId");
		msgExpTime = state.getLong("msgExpTime");
		expirationYear = state.getInt("expirationYear");
		expirationMonth = state.getInt("expirationMonth");
		expirationDay = state.getInt("expirationDay");
		deferredLocation = state.getBoolean("deferredLocation");
		msgLat = state.getDouble("msgLat");
		msgLon = state.getDouble("msgLon");
		msgAlt = state.getDouble("msgAlt");
		currentLat = state.getDouble("currentLat");
		currentLon = state.getDouble("currentLon");
		currentAlt = state.getDouble("currentAlt");
		lastLat = state.getDouble("lastLat");
		lastLon = state.getDouble("lastLon");
		lastAlt = state.getDouble("lastAlt");
		defaultLat = state.getDouble("defaultLat");
		defaultLon = state.getDouble("defaultLon");
		defaultAlt = state.getDouble("defaultAlt");
		msgGeoSpan = state.getInt("msgGeoSpan");
		creatorUsername = state.getString("creatorUsername");
		creatorNickname = state.getString("creatorNickname");
		creatorId = state.getString("creatorId");
		msgCategories = state.getBooleanArray("msgCategories");
		hopCount = state.getInt("hopCount");
		msgRate = state.getDouble("msgRate");
		crcCheck = state.getLong("crcCheck");
		msgTitle = state.getString("msgTitle");
		msgContent = state.getString("msgContent");
		carrierUserName = state.getString("carrierUserName");
		deliveryTime = state.getLong("deliveryTime");
		deliveryLat = state.getDouble("deliveryLat");
		deliveryLon = state.getDouble("deliveryLon");
		deliveryAlt = state.getDouble("deliveryAlt");
		loggedUserName = state.getString("loggedUserName");
		deferredLocation = state.getBoolean("deferredLocation");
		readFlag = state.getBoolean("readFlag");
		deletedFlag = state.getBoolean("deletedFlag");
		synchFlag = state.getBoolean("synchFlag");
		updatedFlag = state.getBoolean("updatedFlag");
		deferredFlag = state.getBoolean("deferredFlag");
		lastTxCopyTime = state.getLong("lastTxCopyTime");
		numberOfTxCopies = state.getInt("numberOfTxCopies");
		blowOnMic = state.getBoolean("blowOnMic");
		spaceUsed = state.getInt("spaceUsed");
		
		attachmentsExtension = state.getString("attachmentsExtension");
		attachmentsPath = state.getString("attachmentsPath");
		
		attachmentsArrayList = (ArrayList<AttachmentElement>) state.getSerializable("attachmentsArrayList");
		adapter.notifyDataSetChanged();
		
		isSameActivity = state.getBoolean("isSameActivity");
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		outState.putLong("msgDropTime", msgDropTime);
		outState.putString("msgId", msgId);
		outState.putLong("msgExpTime", msgExpTime);
		outState.putInt("expirationYear", expirationYear);
		outState.putInt("expirationMonth", expirationMonth);
		outState.putInt("expirationDay", expirationDay);
		outState.putBoolean("deferredLocation", deferredLocation);
		outState.putDouble("msgLat", msgLat);
		outState.putDouble("msgLon", msgLon);
		outState.putDouble("msgAlt", msgAlt);
		outState.putDouble("currentLat", currentLat);
		outState.putDouble("currentLon", currentLon);
		outState.putDouble("currentAlt", currentAlt);
		outState.putDouble("lastLat", lastLat);
		outState.putDouble("lastLon", lastLon);
		outState.putDouble("lastAlt", lastAlt);
		outState.putDouble("defaultLat", defaultLat);
		outState.putDouble("defaultLon", defaultLon);
		outState.putDouble("defaultAlt", defaultAlt);
		outState.putInt("msgGeoSpan", msgGeoSpan);
		outState.putString("creatorUsername", creatorUsername);
		outState.putString("creatorNickname", creatorNickname);
		outState.putString("creatorId", creatorId);
		outState.putBooleanArray("msgCategories", msgCategories);
		outState.putInt("hopCount", hopCount);
		outState.putDouble("msgRate", msgRate);
		outState.putLong("crcCheck", crcCheck);
		outState.putString("msgTitle", msgTitle);
		outState.putString("msgContent", msgContent);
		outState.putString("carrierUserName", carrierUserName);
		outState.putLong("deliveryTime", deliveryTime);
		outState.putDouble("deliveryLat", deliveryLat);
		outState.putDouble("deliveryLon", deliveryLon);
		outState.putDouble("deliveryAlt", deliveryAlt);
		outState.putString("loggedUserName", loggedUserName);
		outState.putBoolean("deferredLocation", deferredLocation);
		outState.putBoolean("readFlag", readFlag);
		outState.putBoolean("deletedFlag", deletedFlag);
		outState.putBoolean("synchFlag", synchFlag);
		outState.putBoolean("updatedFlag", updatedFlag);
		outState.putBoolean("deferredFlag", deferredFlag);
		outState.putLong("lastTxCopyTime", lastTxCopyTime);
		outState.putInt("numberOfTxCopies", numberOfTxCopies);
		outState.putBoolean("blowOnMic", blowOnMic);
		outState.putInt("spaceUsed", spaceUsed);
		
		outState.putString("attachmentsExtension", attachmentsExtension);
		outState.putString("attachmentsPath", attachmentsPath);
		
		outState.putSerializable("attachmentsArrayList", attachmentsArrayList);
		
		outState.putBoolean("isSameActivity", isSameActivity);
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onPause() {
//		msgTitle = msgTitleET.getText().toString();
//		msgContent = msgContentET.getText().toString();
		dbHelper.close(); 
		super.onPause();
	}

	@Override
	protected void onResume() {
		super.onResume();
//		msgTitleET.setText(msgTitle);
//		msgContentET.setText(msgContent);
		dbHelper.open(); 
		if(blowOnMic) {
			dropButton.setText("Drop & Blow");
		}
		else {
			dropButton.setText("Drop");
		}
		
		generalCB.setChecked(msgCategories[0]);
		gamesCB.setChecked(msgCategories[1]);
		advertisementsCB.setChecked(msgCategories[2]);
		suggestionsCB.setChecked(msgCategories[3]);
	 	eventsCB.setChecked(msgCategories[4]);
	 	if(msgGeoSpan==SPAN_100m) {
			span1RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_1km) {
			span2RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_10km) {
			span3RB.setChecked(true);
		}
		else if(msgGeoSpan==SPAN_650km) {
			span4RB.setChecked(true);
		}
			
		msgExpTimeDP.init(expirationYear, expirationMonth, expirationDay, onDateChangedListener);
	}

	@Override
    protected void onStop() {
    	// Unbind from the service
        if (mLocBound) {
            unbindService(mLocServiceConnection);
            mLocBound = false;
        }
        if (mIOBound) {
            unbindService(mIOServiceConnection);
            mIOBound = false;
        }
        super.onStop();
    }
	
    //########################################
    //##      SERVICE CONNECTIONS           ##
    //########################################
    class LocServiceConnection implements ServiceConnection {
    	public void onServiceConnected(ComponentName component, IBinder service) {
    		mILocationEpicService = ILocationEpicService.Stub.asInterface(service);
    	}
    	
    	public void onServiceDisconnected(ComponentName component) {
    		mLocBound = false;
    	}
    };
    
    ServiceConnection mIOServiceConnection = new ServiceConnection() {
    	public void onServiceConnected(ComponentName component, IBinder service) {
    		mIIOEpicService = IIOEpicService.Stub.asInterface(service);
    	}
    	public void onServiceDisconnected(ComponentName component) {
    		mIOBound = false;
    	}
    };
	
    private boolean isAlreadyStarted;
	@Override
	public void onClick(View v) {
		if(v.getId()==R.id.tabnewmsg_epicmsg_viralButton) {
			// check if blow feature is activated (in settings)
			if(blowOnMic) {
				// store message if breath is detected
				if(!isAlreadyStarted) {
					startAudioTest();
					
					animation_IV.setVisibility(View.VISIBLE);
					animation.start();
					
					isAlreadyStarted = true;
				}
				else {
					// do nothing
				}
			}
			else {
				// store message
				spreadSeed();
			}
		}
		// message categories
		if(v.getId()==R.id.tabnewmsg_general_CB) {
			msgCategories[0] = generalCB.isChecked() ? true : false;
		}
		if(v.getId()==R.id.tabnewmsg_games_CB) {
			msgCategories[1] = gamesCB.isChecked() ? true : false;
		}
		if(v.getId()==R.id.tabnewmsg_advertisements_CB) {
			msgCategories[2] = advertisementsCB.isChecked() ? true : false;
		}
		if(v.getId()==R.id.tabnewmsg_suggestions_CB) {
			msgCategories[3] = suggestionsCB.isChecked() ? true : false;
		}
		if(v.getId()==R.id.tabnewmsg_events_CB) {
			msgCategories[4] = eventsCB.isChecked() ? true : false;
		}
		// message geo properties
		if(v.getId()==R.id.tabnewmsg_setGeoButton) {
			// check if data connection is available
			// call mapView activity passing:
			// the set message position or the current position if not yet set
			if(isOnline()) {
				try {
					currentLocation = (Location) mILocationEpicService.refreshLocation();
				} 
				catch (Exception e) {
					e.printStackTrace();
				}
				if(currentLocation!=null) {
					if(deferredLocation) {
						// DO NOTHING
					}
					else {
						msgLat = currentLocation.getLatitude();
        				msgLon = currentLocation.getLongitude();
        				msgAlt = currentLocation.getAltitude();
					}
					Intent mapIntent = new Intent(this, EpicMapActivity.class);
					mapIntent.putExtra("inLat", msgLat);
					mapIntent.putExtra("inLon", msgLon);
					mapIntent.putExtra("settableMsgPosition", true);
					startActivityForResult(mapIntent, MAP_SUBACTIVITY);
				}
				else {
					Toast.makeText(getApplicationContext(), "No Location Available \n" +
        					"please activate GPS or WiFi", Toast.LENGTH_LONG).show();
				}
			}
			else {
				Toast.makeText(getApplicationContext(), "to set message position property \n" +
						"data connection is needed", Toast.LENGTH_LONG).show();
			}
		}
		if(v.getId()==R.id.tabnewmsg_span1_RB) {
			span1RB.setChecked(true);
			msgGeoSpan = SPAN_100m;
			span2RB.setChecked(false); span3RB.setChecked(false); span4RB.setChecked(false);
		}
		if(v.getId()==R.id.tabnewmsg_span2_RB) {
			span2RB.setChecked(true);
			msgGeoSpan = SPAN_1km;
			span1RB.setChecked(false); span3RB.setChecked(false); span4RB.setChecked(false);
		}
		if(v.getId()==R.id.tabnewmsg_span3_RB) {
			span3RB.setChecked(true);
			msgGeoSpan = SPAN_10km;
			span1RB.setChecked(false); span2RB.setChecked(false); span4RB.setChecked(false);
		}
		if(v.getId()==R.id.tabnewmsg_span4_RB) {
			span4RB.setChecked(true);
			msgGeoSpan = SPAN_650km;
			span1RB.setChecked(false); span2RB.setChecked(false); span3RB.setChecked(false);
		}
		// message attachments
		if(v.getId()==R.id.tabnewmsg_attachImage) {
			attachImage();
		}
		if(v.getId()==R.id.tabnewmsg_attachAudio) {
			attachAudio();
		}
		if(v.getId()==R.id.tabnewmsg_attachVideo) {
			attachVideo();
		}
		if(v.getId()==R.id.tabnewmsg_attachFile) {
			attachFile();
		}
		if(v.getId()==R.id.tabnewmsg_takePicture) {
			Toast.makeText(getApplicationContext(), "Take a picture\n...feature not yet available", Toast.LENGTH_LONG).show();
		}
		if(v.getId()==R.id.tabnewmsg_takeAudio) {
			Toast.makeText(getApplicationContext(), "Take audio sample\n...feature not yet available", Toast.LENGTH_LONG).show();
		}
	}  
	
	public void spreadSeed() {
		if(!attachmentsArrayList.isEmpty()) {
			for(int i=0; i<attachmentsArrayList.size(); i++) {
				// copy files from tmpDir directory to msgId directory
				String pathTmp = attachmentsArrayList.get(i).getAttachmentPath();
				File fileTmp = new File(pathTmp);
				String filename = (pathTmp).split("/")[(pathTmp.split("/")).length-1];
            	File cachePath = getApplicationContext().getExternalCacheDir();
            	File msgIdDir = new File(cachePath + "/" + msgId);
            	msgIdDir.mkdirs();
            	String filePath = cachePath + "/" + msgId + "/" + filename;
	    		File fileCopy = new File(filePath);
	   			FileInputStream fis = null;
				try {
					fis = new FileInputStream(fileTmp);
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				}
	   			FileOutputStream fos = null;
	        	try {
	        		fos = new FileOutputStream(fileCopy);
	                copyFile(fis, fos);
	                fis.close();
	                fis = null;
	                fos.flush();
	                fos.close();
	                fos = null;
	                attachmentsArrayList.get(i).setAttachmentPath(filePath);
	            } catch(Exception e) {
	            	Log.e("EpicNewMsg", e.getMessage());
	            }
	        	
				if(i==attachmentsArrayList.size()-1) {
					if(attachmentsExtension==null) {attachmentsExtension = ""; attachmentsPath = "";}
					attachmentsExtension = attachmentsExtension + attachmentsArrayList.get(i).getAttachmentExtension();
					attachmentsPath = attachmentsPath + attachmentsArrayList.get(i).getAttachmentPath();
				}
				else {
					if(attachmentsExtension==null) {attachmentsExtension = ""; attachmentsPath = "";}
					attachmentsExtension = attachmentsExtension + attachmentsArrayList.get(i).getAttachmentExtension() + ",";
					attachmentsPath = attachmentsPath + attachmentsArrayList.get(i).getAttachmentPath() + ",";
				}				
			}
		}
		else {
			attachmentsExtension = null;
			attachmentsPath = null;
		}
		
    	boolean cat_selected = false;
		for(boolean item : msgCategories) {
			if(item) {cat_selected = true; break;}
		}
		if(spaceUsed>=MAX_MSG_SIZE) {Toast.makeText(getApplicationContext(), "To much space used", Toast.LENGTH_LONG).show();}
		else {
			if(!cat_selected) {Toast.makeText(getApplicationContext(), "Check at least one category!", Toast.LENGTH_LONG).show();}
    		else {
    			try {
    				currentLocation = (Location) mILocationEpicService.refreshLocation();
    			} 
    			catch (Exception e) {
    				e.printStackTrace();
    			}
    			if(currentLocation!=null) {
    				Log.d("EpicNewMsg", "currentLocation = " + currentLocation.toString());
    				currentLat = currentLocation.getLatitude();
    				currentLon = currentLocation.getLongitude();
    				currentAlt = currentLocation.getAltitude();
    				if(deferredLocation) {}
    				else {
    					msgLat = currentLocation.getLatitude();
        				msgLon = currentLocation.getLongitude();
        				msgAlt = currentLocation.getAltitude();
    				}
    				storeMessage();
    			}
    			else {
    				Log.d("EpicNewMsg", "currentLocation = null");
//    				Toast.makeText(getApplicationContext(), "No Location Available \n" +
//        					"please activate GPS, WiFi or GPRS", Toast.LENGTH_LONG).show();
    				// show dialog with the following options
    				// 1) deferred sending (as soon as a location is available)
    				// 2) without location
    				// 3) use default location
    				// 4) use last location
    				showLocationMenu();
    			}
    		}
		}
    }
	
	private boolean storeMessage() {
		CurrentUser.readCurrentUserSettings(getApplicationContext());
		creatorUsername = CurrentUser.getCurrentUsername();
		creatorNickname = CurrentUser.getCurrentNickname();
		creatorId = CurrentUser.getMd5ID(getApplicationContext());
		msgRate = CurrentUser.getUserRate();
		
//		dbHelper.open();
		
		msgTitle = msgTitleET.getText().toString();
		msgContent = msgContentET.getText().toString();
		
    	long msgDropTimeMillis = msgDropTime*1000;
    	String msgDropTimeString = DateFormat.getDateTimeInstance().format(msgDropTimeMillis);
		if(msgTitle==null || msgTitle.equals("")) {
			msgTitle = "dropped on " + msgDropTimeString; 
		}
		if(msgContent==null) {msgContent = "";}
		
		deliveryTime = msgDropTime;
		deliveryLat = currentLat;
		deliveryLon = currentLon;
		deliveryAlt = currentAlt;
		String msgCat = "";
		for(int i=0; i<NUMBER_OF_CATEGORIES; i++) {
			msgCat = msgCategories[i] ? msgCat + '1' : msgCat + '0';
		}
		
		// TODO compute CRC
		// msgId, msgExpTime, msgLat, msgLon, msgAlt, msgGeoSpan, msgCat, creatorUsername, creatorNickname,
		// msgTitle, msgContent,
		// attachments' byte stream
		Checksum checksum = new CRC32();
		
		// msgId
		byte[] msgIdByteArray = new byte[6];
		String mac_first_part = msgId.substring(0, 2);
		String mac_second_part = msgId.substring(2,4);
		msgIdByteArray[0] = dbHelper.stringToHex(mac_first_part);
		msgIdByteArray[1] = dbHelper.stringToHex(mac_second_part);
		byte[] time_tag_bytes = dbHelper.intToByteArray(Integer.parseInt(msgId.substring(4)));
		msgIdByteArray[2] = time_tag_bytes[0];
		msgIdByteArray[3] = time_tag_bytes[1];
		msgIdByteArray[4] = time_tag_bytes[2];
		msgIdByteArray[5] = time_tag_bytes[3];
		
		// msgExpTime
		byte[] msgExpTimeByteArray = dbHelper.intToByteArray((int)msgExpTime);
		
		// msgLat/Lon/Alt
		byte[] msgLatByteArray = dbHelper.doubleToByteArray(msgLat);
		byte[] msgLonByteArray = dbHelper.doubleToByteArray(msgLon);
		byte[] msgAltByteArray = dbHelper.doubleToByteArray(msgAlt);
		
		// msgGeoSpan
		byte[] msgGeoSpanByteArray = dbHelper.intToDualByteArray(msgGeoSpan);
		
		// msgCat
		byte[] msgCatByteArray = new byte[2]; 
		int tmp;
    	int cat_val_1 = 0;
    	int cat_val_2 = 0;
    	for(int i = 0; i< 8; i++){
    		if(msgCat.charAt(i) == '1') {
    			cat_val_1 = cat_val_1 + (int) Math.pow(2, 8-i-1);
    		}
    	}
    	for(int i = 8; i< 16; i++){
    		if(msgCat.charAt(i) == '1') {
    			cat_val_2 = cat_val_2 + (int) Math.pow(2, 16-i-1);
    		}
    	}
    	msgCatByteArray[0] = (byte) cat_val_1;
    	msgCatByteArray[1] = (byte) cat_val_2;
    	
    	// creatorId
    	byte[] creatorIdByteArray = new byte[16];
    	int length = creatorId.length();
    	for(int i=0; i<16; i++) {
    		if(i < length){
    			byte a = (byte) creatorId.charAt(i);
    			creatorIdByteArray[i] = a;
    		} else {		
    			byte a = (byte) ' ';
    			creatorIdByteArray[i] = a;
    		}
    	}
    	
    	// creatorNickname
    	byte[] creatorNicknameByteArray = new byte[16];
    	length = creatorNickname.length();
    	for(int i=0; i<16; i++) {
    		if(i < length){
    			byte a = (byte) creatorNickname.charAt(i);
    			creatorNicknameByteArray[i] = a;
    		} else {		
    			byte a = (byte) ' ';
    			creatorNicknameByteArray[i] = a;
    		}
    	}
    	
    	// msgTitle/Content
    	byte[] msgTitleByteArray = msgTitle.getBytes();
    	byte[] msgContentByteArray = msgContent.getBytes();
    	
    	checksum.update(msgIdByteArray, 0, msgIdByteArray.length);
		checksum.update(msgExpTimeByteArray, 0, msgExpTimeByteArray.length);
		checksum.update(msgLatByteArray, 0, msgLatByteArray.length);
		checksum.update(msgLonByteArray, 0, msgLonByteArray.length);
		checksum.update(msgAltByteArray, 0, msgAltByteArray.length);
		checksum.update(msgGeoSpanByteArray, 0, msgGeoSpanByteArray.length);
		checksum.update(msgCatByteArray, 0, msgCatByteArray.length);
		checksum.update(creatorIdByteArray, 0, creatorIdByteArray.length);
		checksum.update(creatorNicknameByteArray, 0, creatorNicknameByteArray.length);
//		checksum.update(msgTitleByteArray, 0, msgTitleByteArray.length);
//		checksum.update(msgContentByteArray, 0, msgContentByteArray.length);
    	
    	// attachments' byte stream
		if(attachmentsPath!=null) {
	    	String[] pathOfFiles = attachmentsPath.split(",");
			int numberOfAttachments = pathOfFiles.length;
			byte[] fileByteArray;
			for(int i=0; i<numberOfAttachments; i++) {
				fileByteArray = null;
				File fileTmp = new File(pathOfFiles[i]);
				fileByteArray = dbHelper.getByteArrayFromFile(getApplicationContext(), pathOfFiles[i]);
				checksum.update(fileByteArray, 0, fileByteArray.length);
		    }
		}
		crcCheck = checksum.getValue();
		if(
			dbHelper.addContent(msgId, msgExpTime, msgLat, msgLon, msgAlt, msgGeoSpan, 
			msgCat, 
			creatorId, // creator ID
			msgTitle, msgContent, attachmentsExtension, attachmentsPath,
			0, // hopCount...but I'm the creator 
			creatorId, // carrier ID = creator ID
			deliveryTime, deliveryLat, deliveryLon, deliveryAlt, 
			creatorId, // logged ID = creator ID
			true, false, false, false, // readFlag, deletedFlag, synchFlag, updatedFlag,
			deferredFlag, 
			lastTxCopyTime, numberOfTxCopies, // TODO lastTxTime = {0, msgDropTime} => no copy sent = {very high priority, high priority}
			msgRate,
			creatorNickname, 
			msgRate, // my rate...but I'm the creator 
			spaceUsed,
			crcCheck)
			==-1) {
			
//			dbHelper.close(); 
			Log.e("EpicNewMsg", "An error occurs adding the content"); 
			return false;
			
		}
		else {
//			dbHelper.close();
			finish();
			return true;
		}
	}
	
	//#############################//
    // attachments utility methods // 
    //#############################//
    private void attachImage() {
    	Intent intent = new Intent();
    	intent.setType("image/*");
    	intent.setAction(Intent.ACTION_GET_CONTENT);
    	startActivityForResult(Intent.createChooser(intent, "Select image"), ATTACH_IMAGE);
    }
    private void attachAudio() {
    	Intent intent = new Intent();
    	intent.setType("audio/*");
    	intent.setAction(Intent.ACTION_GET_CONTENT);
    	startActivityForResult(Intent.createChooser(intent, "Select audio"), ATTACH_AUDIO);
    }
    private void attachVideo() {
    	Intent intent = new Intent();
    	intent.setType("video/*");
    	intent.setAction(Intent.ACTION_GET_CONTENT);
    	startActivityForResult(Intent.createChooser(intent, "Select video"), ATTACH_VIDEO);
    }
    private void attachFile() {
    	Intent intent = new Intent();
    	intent.setType("*/*");
    	intent.setAction(Intent.ACTION_GET_CONTENT);
    	startActivityForResult(Intent.createChooser(intent, "Select file"), ATTACH_FILE);
    }
    
    //########################
    // addAttachments method # 
    //########################
    private static final int MAX_IMAGE_WIDTH = 480;
    private static final int MAX_IMAGE_HEIGHT = 600;
    public void addAttachments(Uri selectedUri, int requestCode) { 
	    String selectedPath = getPath(selectedUri, requestCode);
	    String fileExtension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(selectedPath); 
	//    String mimeType = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
	    long fSize = getFileSize(selectedUri, requestCode);
	    
	    String filename = selectedPath.split("/")[(selectedPath.split("/")).length-1];
		File cachePath = getApplicationContext().getExternalCacheDir();
		File tmpDir = new File(cachePath + "/" + tmpDirString);
		if(!tmpDir.exists()) {tmpDir.mkdirs();}
		    String filePath = tmpDir + "/" + filename;
		    
		    Log.d("EpicNewMsg", "filePath = " + filePath);
		    
	    if(fSize>0 && FileExtensionMap.getSingelton().hasExtension(fileExtension)) {
	    	File fileTmp;
	    	File fileCopy;
	    	boolean isCompressed = false;
	    	if(fileExtension.equals("fig")||fileExtension.equals("jpeg")||fileExtension.equals("jpg")||fileExtension.equals("png")||
	    			fileExtension.equals("bmp")||fileExtension.equals("gif")) {
	    		Bitmap filebmpSource;
	        	Bitmap filebmpCompressed;
	        	BitmapFactory.Options bfo = new BitmapFactory.Options();
	        	bfo.outWidth = MAX_IMAGE_WIDTH;
	        	bfo.outHeight = MAX_IMAGE_HEIGHT;
	    		filebmpSource = BitmapFactory.decodeFile(selectedPath, bfo);
	    		int width = filebmpSource.getWidth();
	    		int height = filebmpSource.getHeight();
	    		Log.d("EpicNewMsg", "Original image width and height = " + width + ", " + height);
	    		if(width>MAX_IMAGE_WIDTH) {
	    			if(height>MAX_IMAGE_HEIGHT) {
	    				FileOutputStream osTmp;
						try {
							fileExtension = "png";
							String[] tmp = filename.split("\\.");
							filename = "";
							for(int i=0; i<tmp.length-1; i++) {
								filename = filename + tmp[i];
							} 
							filename = filename + "." + fileExtension;
							filePath = cachePath + "/" + tmpDirString + "/" + filename;
							osTmp = new FileOutputStream(filePath);
							int compressedWidth = MAX_IMAGE_WIDTH;
	        				int compressedHeight = (int)((float)height*(float)((float)compressedWidth/(float)width));
	        				filebmpCompressed = Bitmap.createScaledBitmap(filebmpSource, compressedWidth, compressedHeight, false);
	        				filebmpCompressed.compress(CompressFormat.PNG, 100, osTmp);
	        				osTmp.flush();
	        				osTmp.close();
	        				osTmp = null;
	        				fileCopy = new File(filePath);
	        				fSize = fileCopy.length();
	        				isCompressed = true;
						} catch (FileNotFoundException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
	    			}
	    			else {isCompressed = false;}
	    		}
	    		else if(height>MAX_IMAGE_HEIGHT) {isCompressed = false;}
	    		else {isCompressed = false;}
	    	}
	    	else {isCompressed = false;}
	    	if(!isCompressed) {
	    		fileTmp = new File(selectedPath);
	    		fileCopy = new File(filePath);
	   			FileInputStream fis = null;
				try {fis = new FileInputStream(fileTmp);} catch (FileNotFoundException e1) {e1.printStackTrace();}
	   			FileOutputStream fos = null;
	        	try {
	        		fos = new FileOutputStream(fileCopy);
	                copyFile(fis, fos);
	                fis.close();
	                fis = null;
	                fos.flush();
	                fos.close();
	                fos = null;
	            } catch(Exception e) {Log.e("EpicNewMsg", e.getMessage());}
	    	}
	        spaceUsed = (int) (spaceUsed + fSize);
	        Log.d("EpicNewMsg", "spaceUsed="+spaceUsed);
	        if(spaceUsed>MAX_MSG_SIZE) {
	        	spaceUsed = (int) (spaceUsed - fSize);
	        	Toast.makeText(getApplicationContext(), "Sorry!\n" +
	        			"Not enough space for this attachment!", Toast.LENGTH_LONG).show();
	        	File file = new File(filePath);
	        	if(file.delete()) {
	        		Log.d("EpicNewMsg", "file copy deleted because not enough space available");
	        		if(attachmentsArrayList.isEmpty()) {
	//               	    String dirPath = cachePath + "/" + msgId;
	        			String dirPath = cachePath + "/" + tmpDirString;
	               	    File dir = new File(dirPath);
	               	    if(dir.delete()) {Log.d("EpicNewMsg", "dir.delete(): directory deleted");}
	               	    else {Log.d("EpicNewMsg", "dir.delete(): directory NOT deleted");}
					}
	        	}
	        	else {Log.d("EpicNewMsg", "file copy NOT deleted even though not enough space available");}
	        }
	        else {
	        	AttachmentElement attachmentElement = new AttachmentElement(fileExtension, // file extension
						selectedPath, (int)fSize, // original path and size
						filePath, (int)fSize); // new path and compressed size (same file type)
	        	attachmentsArrayList.add(attachmentElement);
	        	adapter.notifyDataSetChanged();
	        }
	    }
	    else {Toast.makeText(getApplicationContext(), "Sorry!\n" + "Unable to attach this file!", Toast.LENGTH_LONG).show();}
    }
    //##################//
    // onActivityResult // 
    //##################//
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent returnedIntent) { 
        super.onActivityResult(requestCode, resultCode, returnedIntent);
        if(requestCode==ATTACH_IMAGE || requestCode==ATTACH_AUDIO || requestCode==ATTACH_VIDEO || requestCode==ATTACH_FILE) {
        	if(resultCode == RESULT_OK) {  
                Uri selectedUri = returnedIntent.getData();
                addAttachments(selectedUri, requestCode);
            }
        }
        else if(requestCode==MAP_SUBACTIVITY) {
    		if(resultCode == RESULT_OK) {
    			msgLat = returnedIntent.getDoubleExtra("outLat", 0);
    			msgLon = returnedIntent.getDoubleExtra("outLon", 0);
    			deferredLocation = true;
    		}
    		else {}
        }
    }
    
    // COPY A FILE
    private void copyFile(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int read;
        while((read = in.read(buffer)) != -1){
          out.write(buffer, 0, read);
        }
    }
    
    //############################################//
    // methods to retrieve path and size from URI // 
    //############################################//
    public String getPath(Uri uri, int type) {
     	String path = null;
        File fileTmp = new File(uri.getPath());
        Log.d("EpicNewMsg", "fileTmp.exists()="+fileTmp.exists());
        if(fileTmp.exists()) {
        	path = uri.getPath();
        }
        else {
        	if(type==ATTACH_IMAGE || type==ATTACH_AUDIO || type==ATTACH_VIDEO || type==ATTACH_FILE) {
        		if ("content".equalsIgnoreCase(uri.getScheme())) {
         			String[] projection = { "_data" };
                    Cursor cursor = null;
                    
                    try {
                    	cursor = getApplicationContext().getContentResolver().query(uri, projection, null, null, null);
                        int column_index = cursor.getColumnIndexOrThrow("_data");
                        if (cursor.moveToFirst()) {path = cursor.getString(column_index);}
                    } catch (Exception e) {}
                }
                else if ("file".equalsIgnoreCase(uri.getScheme())) {path = uri.getPath();}
        	}
        }
        return path;
    }
    
    public long getFileSize(Uri uri, int type) {
   	   //return the size in bytes of the file attacched to the URI passed as method's argument
      	long fileSize = 0;
      	String path = getPath(uri, type);
      	File file = new File(path);
      	if(file.exists()) {fileSize = file.length();}
      	else {
      		path = "file://" + path;
      		file = new File(path);
      		if(file.exists()) {fileSize = file.length();}
      	}
   	    return fileSize;
   	}
    
    
    //##########
    // Dialogs #
    //##########	
    public void showLocationMenu() {
  		showDialog(CONTEXT_MENU_LOCATION_ID);
  	}
    
    @Override
    protected Dialog onCreateDialog(int id) {
	    if(id == CONTEXT_MENU_LOCATION_ID) {
			if(iconContextMenu_location==null) {
			    iconContextMenu_location = new IconContextMenu(this, CONTEXT_MENU_LOCATION_ID);
			    iconContextMenu_location.addItem(res, "Deferred sending", R.drawable.icon, DEFERRED_LOCATION);
			    iconContextMenu_location.addItem(res, "Send without location", R.drawable.icon, WITHOUT_LOCATION);
			    iconContextMenu_location.addItem(res, "Send with default location", R.drawable.icon, DEFAULT_LOCATION);
			    Location lastLocation = null;
				try {
					lastLocation = (Location) mILocationEpicService.getLastKnownLocation();
				} 
				catch (Exception e) {
					e.printStackTrace();
				}
			    if(lastLocation!=null) {
			    	lastAlt = lastLocation.getAltitude();
			    	lastLat = lastLocation.getLatitude();
			    	lastLon = lastLocation.getLongitude();
			    	String lastLocationDate = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(lastLocation.getTime());
			    	iconContextMenu_location.addItem(res, "Send with last known location: " +
			    			lastLocationDate, R.drawable.icon, LAST_LOCATION);
			    }
	    	}
		    iconContextMenu_location.setOnClickListener(new IconContextMenu.IconContextMenuOnClickListener() {
	            public void onClick(int menuId) {
		    		switch(menuId) {
	                	case DEFERRED_LOCATION: { 
	                		deferredFlag = true;
	                		msgAlt = 0; msgLat = 0; msgLon = 0;
	                		currentAlt = 0; currentLat = 0; currentLon = 0;
	                		storeMessage();
	                		break; 
	                	}
	                	case WITHOUT_LOCATION: { 
	                		deferredFlag = false; 
	                		msgAlt = 0; msgLat = 0; msgLon = 0;
	                		currentAlt = 0; currentLat = 0; currentLon = 0;
	                		storeMessage(); 
	                		break; 
	                	}
	                	case DEFAULT_LOCATION: {
	                		CurrentUser.readCurrentUserSettings(getApplicationContext());
	                        defaultLat = CurrentUser.getDefaultMsgLatitude();
	                        defaultLon = CurrentUser.getDefaultMsgLongitude();
	                        defaultAlt = CurrentUser.getDefaultMsgAltitude();
	                        deferredFlag = false; 
	                		msgAlt = defaultAlt; msgLat = defaultLat; msgLon = defaultLon;
	                		currentAlt = 0; currentLat = 0; currentLon = 0;
	                		storeMessage();
	                		break; 
	                	}
	                	case LAST_LOCATION: { 
	                		deferredFlag = false; 
	                		msgAlt = lastAlt; msgLat = lastLat; msgLon = lastLon;
	                		currentAlt = lastAlt; currentLat = lastLat; currentLon = lastLon;
	                		storeMessage();
	                		break; 
	                	}
	                }
	            }
		    });
	    	return iconContextMenu_location.createMenu(res, "Location not available!\nChoose how to localize it");
		}
		
	    return super.onCreateDialog(id);
	}
  	
  	// check if there is data connection
  	public boolean isOnline() {
  		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  		NetworkInfo ni = cm.getActiveNetworkInfo();
  		if(ni != null){
  			return cm.getActiveNetworkInfo().isConnectedOrConnecting();
  		}
  		else {
  			return false;
  		}
  	}
  	
  	//#################
  	// BLOW ANIMATION #
  	//#################
  	public class MyAnimationDrawable extends AnimationDrawable {
    	private volatile int duration;//its volatile because another thread will update its value
    	private int currentFrame;
    	public MyAnimationDrawable() {
    	    currentFrame = 0;
    	}
    	@Override
    	public void run() {
    	    int n = getNumberOfFrames();
    	    currentFrame++;
    	    if(stopAnimation) {
	        	Log.d("audioTest", "currentFrame after blow detection = " + currentFrame);
	        	if(currentFrame >= n) {
	        		if(!isFirst) {
	        			isLast = true;
	        			Log.d("audioTest", "isLast = true");
	        		}
	        	} 
	        }
    	    if (currentFrame >= n) {
    	        currentFrame = 0;
    	    }
    	    
    	    if(!stopAnimation) {
    	    	unscheduleSelf(this);
    	    	selectDrawable(currentFrame);
    	    	scheduleSelf(this, SystemClock.uptimeMillis() + duration);
    	    }
    	    else {
    	    	if(isFirst) {
	    	    	frame = res.getDrawable(R.drawable.dfive); 
					animation.addFrame(frame, 400);
					frame = res.getDrawable(R.drawable.dsix); 
					animation.addFrame(frame, 400);
					frame = res.getDrawable(R.drawable.dseven); 
					animation.addFrame(frame, 400);
					frame = res.getDrawable(R.drawable.deight); 
					animation.addFrame(frame, 400);
					Log.d("audioTest", "frames added");
					isFirst = false;
    	    	}
				if(!isLast) {
	    	    	unscheduleSelf(this);
	    	    	selectDrawable(currentFrame);
	    	    	scheduleSelf(this, SystemClock.uptimeMillis() + duration);
				}
				else {
					// do nothing: don't call again the run method
					unscheduleSelf(this);
					stopAudioTest();
					animation.stop();
					Log.d("audioTest", "stop animation");
					animation_IV.setVisibility(View.GONE);
				}
    	    }
    	}

    	public void setDuration(int duration)
    	{
    	    this.duration = duration;
    	    //we have to do the following or the next frame will be displayed after the old duration
    	    unscheduleSelf(this);
    	    selectDrawable(currentFrame);
    	    scheduleSelf(this, SystemClock.uptimeMillis()+duration);
    	}
    }
  	
  	//#################
  	// BLOW DETECTION #
  	//#################
  	public void startAudioTest() {
		if(recordSignalThread!=null) {
			recordSignalThread.stop();
			recordSignalThread.cancel();
			recordSignalThread = null;
		}
		if(processSignalThread!=null) {
			processSignalThread = null;
		}
		recordSignalThread = new RecordSignal();
		processSignalThread = new ProcessSignal();
		new Thread(recordSignalThread).start();
		new Thread(processSignalThread).start();
		isRecording = true;
		isProcessing = true;
		Toast.makeText(getApplicationContext(), "Blow on microphone\nto make message viral", Toast.LENGTH_LONG).show();
	}
	
	public void stopAudioTest() {
		isRecording = false;
		isProcessing = false;
		if(processSignalThread!=null) {
			processSignalThread = null;
		}
		if(recordSignalThread!=null) {
			recordSignalThread.cancel();
			recordSignalThread = null;
		}
		// store message
		spreadSeed();
	}
	
	private static int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
	private static int format = AudioFormat.ENCODING_PCM_16BIT;
	private static int Fs = 16000;
	private static int minBufferSize;
	private AudioRecord audioInput; 
	private boolean isRecording;
	private boolean isProcessing;
	private boolean isNewAudioFragment;
    
	private final static int bytesPerSample = 2; // As it is 16bit PCM
	private final double amplification = 1.0; // choose a number as you like
	private static int frameLength = 512; // number of samples per frame => 32[ms] @Fs = 16[KHz]
	private static int windowLength = 16; // number of frames per window => 512[ms] @Fs = 16[KHz]
	private static int maxBufferedWindows = 8; // number of buffered windows => 4096 [ms] @Fs = 16[KHz]
    
	private static int bufferSize = frameLength*bytesPerSample;
	private static double[] hannWindow = new double[frameLength*bytesPerSample];
    
	private Queue<byte[]> queue = new LinkedList<byte[]>();
//    Semaphore semaphoreRecord = new Semaphore(1, true);
	private Semaphore semaphoreProcess = new Semaphore(0, true);
    
	private double[] rmsArray = new double[windowLength];
	private Queue<double[]> rmsQueue = new LinkedList<double[]>();
    
	private RecordSignal recordSignalThread;
	private ProcessSignal processSignalThread;
    
    public static class RecorderSingleton {
	    public static RecorderSingleton instance = new RecorderSingleton();
	    private AudioRecord recordInstance = null;
	    
	    private RecorderSingleton() {
	    	minBufferSize = AudioRecord.getMinBufferSize(Fs, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
	    	while(minBufferSize>bufferSize) {
	    		bufferSize = bufferSize*2;
	    	}
	    }
	    
	    public boolean init() {
	        recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, Fs, channel_config, format, bufferSize);
	    	if (recordInstance.getState() != AudioRecord.STATE_INITIALIZED) {
	    		Log.d("audiotestActivity", "Fail to initialize AudioRecord object");
	    		Log.d("audiotestActivity", "AudioRecord.getState()=" + recordInstance.getState());
	    	}
	        if (recordInstance.getState() == AudioRecord.STATE_UNINITIALIZED) {
	            return false;
	        }
	        return true;
	    }
	    
	    public int getBufferSize() {return bufferSize;}
	    
	    public boolean start() {
	        if (recordInstance != null && recordInstance.getState() != AudioRecord.STATE_UNINITIALIZED) {
	            if (recordInstance.getRecordingState() != AudioRecord.RECORDSTATE_STOPPED) {
	                recordInstance.stop();
	            }
	            recordInstance.release();
	        }
	        if (!init()) {
	            return false;
	        }
	        recordInstance.startRecording();
	        return true;
	    }
	    public int read(byte[] audioBuffer) {
	        if (recordInstance == null) {
	            return AudioRecord.ERROR_INVALID_OPERATION;
	        }
	        int ret = recordInstance.read(audioBuffer, 0, bufferSize);
	        return ret;
	    }
	    public void stop() {
	        if (recordInstance == null) {
	            return;
	        }
	        if(recordInstance.getState()==AudioRecord.STATE_UNINITIALIZED) {
	        	Log.d("AudioTest", "instance uninitialized");
	        	return;
	        }
	        if(recordInstance.getState()==AudioRecord.STATE_INITIALIZED) {
	        	recordInstance.stop();
		        recordInstance.release();
	        }
	    }
	}
	
	public class RecordSignal implements Runnable {
		private boolean cancelled = false;
	    public void run() {
	    	Looper.prepare();
	        // We're important...
//	        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
	        int bufferRead = 0;
	        byte[] inAudioBuffer;
	        if (!RecorderSingleton.instance.start()) {
	            return;
	        }
	        try {
	            Log.d("audiotestActivity", "Recorder Started");
	            while(isRecording) {
	            	inAudioBuffer = null;
	            	inAudioBuffer = new byte[bufferSize];
	                bufferRead = RecorderSingleton.instance.read(inAudioBuffer);
	                if (bufferRead == AudioRecord.ERROR_INVALID_OPERATION) {
	                    throw new IllegalStateException("read() returned AudioRecord.ERROR_INVALID_OPERATION");
	                } else if (bufferRead == AudioRecord.ERROR_BAD_VALUE) {
	                    throw new IllegalStateException("read() returned AudioRecord.ERROR_BAD_VALUE");
	                }
                	queue.add(inAudioBuffer);
	                semaphoreProcess.release();
	            }
	        } 
	        finally {
	            // Close resources...
	            stop();
	        }
	        Looper.loop();
	    }
	    public void stop() {
	        RecorderSingleton.instance.stop();
	    }
	    public void cancel() {
	        setCancelled(true);
	    }
		public boolean isCancelled() {
			return cancelled;
		}
		public void setCancelled(boolean cancelled) {
			this.cancelled = cancelled;
		}
	}
	
	public class ProcessSignal implements Runnable {
	    public void run() {
	    	Looper.prepare();
//	        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT);
	    	int rmsIndex = 0;
	    	while(isProcessing) {
				try {
					semaphoreProcess.acquire();
					byte[] outAudioBuffer = new byte[frameLength*bytesPerSample*(bufferSize/(frameLength*bytesPerSample))];
					outAudioBuffer = queue.element();
					if(queue.size()>0) {
						for(int index=0; index<bufferSize/(frameLength*bytesPerSample); index++) {
							byte[] frameTmp = new byte[frameLength*bytesPerSample];
							System.arraycopy(outAudioBuffer, index*(frameLength*bytesPerSample), frameTmp, 0, frameLength*bytesPerSample);
							double rms = 0.0;
							rms = computeRMS(frameTmp);
							if(rmsIndex==windowLength-1) {
								rmsArray[rmsIndex] = rms;
								rmsQueue.add(rmsArray);
								rmsIndex = 0;
							}
							else {
								rmsArray[rmsIndex] = rms;
								rmsIndex++;
							}
//							Log.d("test", "test, rmsQueue.size="+rmsQueue.size());
							double thRMS = 0.4;
							if(rmsQueue.size()==2) {
								int aboveThCounter = 0;
								double tmpMean = 0.0; 
								double[] tmp1 = rmsQueue.poll();
								double[] tmp2 = rmsQueue.poll();
								for(int i=0; i<tmp1.length; i++) {
									tmpMean = tmpMean + tmp1[i];
									tmpMean = tmpMean + tmp2[i];
									if(tmp1[i]>thRMS) {
										aboveThCounter++;
									}
									if(tmp2[i]>thRMS) {
										aboveThCounter++;
									}
								}
								double thRatio = 0.7;
								double occurRatio = (double)((double)aboveThCounter/((double)tmp1.length*2.0));
								Log.d("mean rms", "mean rms = " + tmpMean/((double)tmp1.length*2.0));
								Log.d("above th(=" + thRatio + ") occur", "occur ratio = " + occurRatio);
								
								if(!stopAnimation) {
									if(occurRatio<0.2) {
										animation.setDuration(400);
									}
									else if (occurRatio>=0.2 && occurRatio<0.6) {
										animation.setDuration(200);
									}
									else if (occurRatio>=0.6 && occurRatio<=1) {
										animation.setDuration(100);
									}
								}
								
								if(occurRatio>thRatio) {
									// send message
									Log.d("BlowDetected", "Blow detected!!! ");
									stopAnimation = true;
								}
							}
						}
					}
					else {
						rmsIndex = 0;
						isNewAudioFragment = true;
					}
				    if(isNewAudioFragment) {
				    	rmsQueue.clear();
				    	isNewAudioFragment = false;
				    }
				    queue.poll();
				} 
				catch (InterruptedException e) {
					e.printStackTrace();
				}
	    	}
	    	Looper.loop();
	    }
	}
	
	public double computeRMS(byte[] byteFrame) {
		//rms(frameIndex) = sqrt( (1/frameLength) * sum(frames(i,:).^2) );
		double rms = 0;
		double[] micBufferData = new double[frameLength];
		for (int index = 0, floatIndex = 0; index < frameLength*bytesPerSample - bytesPerSample + 1; 
	    		index += bytesPerSample, floatIndex++) {
	        double sample = 0;
	        for (int b = 0; b < bytesPerSample; b++) {
	            int v = byteFrame[index + b];
	            if (b < bytesPerSample - 1 || bytesPerSample == 1) {
	                v &= 0xFF;
	            }
	            sample += v << (b * 8);
	        } 
	        double sample32 = amplification * (sample / 32768.0);
	        micBufferData[floatIndex] = sample32;
	        rms = rms + Math.pow(sample32, 2);
	    }
		rms = Math.sqrt(rms/frameLength);
//		Log.d("audiotestActivity", "rms value: "+rms);
		return rms;
	}
	
	
	
	
	@Override
	public void onTabChanged(String tabId) {
		
		setTabColor(this.getTabHost());
	}
	
	
	public static void setTabColor(TabHost tabhost) {
	    for(int i=0;i<tabhost.getTabWidget().getChildCount();i++)
	    {
	    	
	        tabhost.getTabWidget().getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff")); //unselected
	    }
	    tabhost.getTabWidget().getChildAt(tabhost.getCurrentTab()).setBackgroundColor(Color.parseColor("#37c0a2")); // selected
	}
	
	
	
	
}  